Project1-Hog
实现一个掷骰子游戏
规则
两位玩家依次掷任意数量(不多于10个)骰子,点数之和先达到GOAL的胜利。
- Sow Sad: 若其中一个骰子点数为一,则该玩家此轮得分为1
- Boar Brawl:
玩家可以选择不掷骰子,得分为
max(1,3*abs(对手得分十位数-自己得分个位数)),位数不够补零。 - Sus Fuss: 若一局结束后,玩家点数数值有三或四个因数(包括1和点数本身),该玩家点数会变为比当前数值大的最近的一个质数
Phase 1: Rules of the Game
模拟游戏的进行
Problem 0
熟悉dice.py,了解骰子的生成
- make_fair_dice(
)用于生成每面概率相等的SIDE面骰子 - make_test_dice(
)用于测试循环投出一系列指定值
掷出一次骰子的方法:调用生成骰子赋值给的变量e.g. six_sided()
Problem 1
实现掷骰子函数,并实现规则Sow Sad
在定义函数时,若出现形参后已经赋值的情况,该值代表该函数不传入参数时形参默认值
如
def roll_dice(num_rolls, dice=six_sided),若不传入dice参数则默认为six_sided
roll_dice()函数:
参数:
- num_rolls指掷骰子次数
- dice指传入的骰子(默认值为六面骰子)
理解:
- 该函数返回的是num_roll次结果之和,若其中有1则返回1
- 若上次调用函数掷骰子次数少于掷骰子次数,则下次掷骰子时会接着上次开始而非从头开始
- 在循环中return语句会结束一个循环
My code:
1 | def roll_dice(num_rolls, dice=six_sided): |
Problem 2
实现规则Boar Brawl
boar_brawl()函数:
参数:
- player_score:自己的分数
- opponent_score:对手的分数
理解:
- 获取自己分数的个位数与对手分数的十位数
- 相减并取绝对值后乘三
- 若小于1则输出1,否则输出计算结果
My code:
1 | def boar_brawl(player_score, opponent_score): |
注意:传入的参数不一定是十位数,需要进行一些处理
Problem 3
实现函数,将前两个规则结合,输出正确结果
take_turn()函数:
参数:
- num_rolls:掷骰子次数
- player_score:自己的分数
- opponent_score:对手的分数
- dice:使用的骰子
理解:
- 若num_rolls>0,则按照正常规则进行,获得本轮掷骰点数之和
- 若num_rolls=0,即不掷骰子,等同于选择使用Boar Brawl规则,执行该函数
My code:
1 | def take_turn(num_rolls, player_score, opponent_score, dice=six_sided): |
Problem 4
实现Sus Fuss规则
num_factors()函数:
参数:
- n:要计算的数n
理解:
- 返回数n的因数个数
- 1和n本身也算进去
My code:
1 | def num_factors(n): |
sus_points()函数:
参数:
- score:某玩家的分数
理解:
- 该函数用于更新玩家在Sus Fuss规则下新的分数
- 即用于判断符合条件下大于该分数数值的下一个质数
- 若该数值不符合条件,则返回本身
My code:
1 | def sus_points(score): |
sus_update()函数:
参数:
- num_rolls:掷骰子次数
- player_score:自己的分数
- opponent_score:对手的分数
- dice:使用的骰子
理解:
- 用于输出num_rolls次掷骰子后,考虑以上三种规则后的点数之和
- 现根据take_turn()函数求出满足前两个规则的本轮分数之和,并累加到当前分数上
- 再判断此时分数是否满足第三个规则,进行相应分数改动
My code:
1 | def sus_update(num_rolls, player_score, opponent_score, dice=six_sided): |
Problem 5
完整实现游戏模拟
play()函数:
参数:
- strategy0:player0使用的策略
- strategy1:player1使用的策略
- update:使用的更新函数(有无sus)
- score0:player0的起始分数
- score1:player1的起始分数
- dice:使用的骰子
- goal:实现游戏结束的数值
理解:
- strategy指的是玩家掷骰子数量
- strategy函数传入自己与对手的分数,根据两者分数得出下次掷骰子数量
- 使用传入的update函数来决定分数改变策略(是否采用sus fuss规则)
My code:
1 | def play(strategy0, strategy1, update, |
Phase 2: Strategies
这部分将会根据自己与对手的分数生成每轮玩家的掷骰数(0-10)
Problem 6
返回一个函数,获取自己与对手分数并输出指定骰子个数
理解:
- 返回的是函数,有两个参数:自己与对手分数
- 无论两者分数多少,返回的总是一开始传入的指定骰子个数
My code:
1 | def always_roll(n): |
Problem 7
判断每种分数组合是否都有一种对应的掷骰个数(分数组合指一种自己与对手的分数)
is_always_roll()函数:
参数:
- strategy:掷骰策略
- goal:玩家胜利要达到的目标分数
理解:
- 自己与对手的得分在胜利之前可能性均有100种(0-99),故可能性组合有10000种
- 该函数实现了判断每种可能性组合下返回的掷骰数是否相同
- goal不一定是100
My code:
1 | def is_always_roll(strategy, goal=GOAL): |
Problem 8
返回一个函数,用来调用n次掷骰函数,并返回这n次掷骰得到的值之和的平均值
语法特性:*args
*args参数允许函数接受任意数量的位置参数,以元组形式传入
args可以改为其他名称,*必须有
应用:
- 定义的函数接受不定数量位置参数时
- 编写高阶函数(higher-order function)时,传递参数给内部的定义的函数
make_averaged()函数
参数:
- original_function:调用的掷骰函数
- times_called:调用次数
理解:
- 函数需要做到执行n次掷骰函数,并将返回值累加,最后求这n次和的平均值
- 在内联函数中使用了*args来表示若干参数,与调入的掷骰函数参数数量一致
My code:
1 | def make_averaged(original_function, times_called=1000): |
Problem 9
实现函数,枚举掷骰次数(1-10),看哪次的分数平均值最大
max_scoring_num_rolls()函数
参数:
- dice:使用的骰子
- times_called:调用次数
理解
- 遍历掷骰次数,调用make_averaged函数计算平均值,取1-10掷骰次数中平均值最大值
- 当平均值相等时取更小的
My code:
1 | def max_scoring_num_rolls(dice=six_sided, times_called=1000): |
Problem 10
采用Boar Brawl规则,若roll出0时根据该规则得到的分数比threshold大,返回0,否则返回掷骰次数
boar_strategy()函数
参数:
- score:自己的分数
- opponent_score:对手的分数
- threshold:阈值分数,若采用boar brawl得到的分数大于它则返回掷骰0次
- num_rolls:掷骰次数
理解:
- boar brawl规则是在掷骰0次下的特殊规则
- 若采用该规则策略获得的分数要比正常掷骰获得的分数更高,就采用该策略(返回掷骰次数0次)
- 否则按正常掷骰次数掷骰
My code:
1 | def boar_strategy(score, opponent_score, threshold=11, num_rolls=6): |
Problem 11
采用Sus Fuss规则,若roll出0时根据该规则与Boar Brawl规则得到的分数与起始分数差值比threshold大,返回0,否则返回掷骰次数
sus_strategy()函数
参数:
- score:自己的分数
- opponent_score:对手的分数
- threshold:阈值分数,若采用boar brawl得到的分数大于它则返回掷骰0次
- num_rolls:掷骰次数
理解:
- 即在boar brawl规则下采用sus fuss规则得到分数
- 若采用该规则策略获得的分数要比正常掷骰获得的分数更高,就采用该策略(返回掷骰次数0次)
- 否则按正常掷骰次数掷骰
My code:
1 | def sus_strategy(score, opponent_score, threshold=11, num_rolls=6): |
Problem 12
结合上述所有策略与自己的策略,实现最终策略
My code:
1 | def final_strategy(score, opponent_score): |